/*
 * Copyright 2024 ywcai
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

`include "../core/defines.v"
`include "axi_defines.v"
`timescale 1ns/1ps

module axi_master_mux(
	input	wire[`AxiDataBus]			m_rd_data_i,
	input	wire[1:0]					m_errcode_i,

	input	wire						m0_we_i,
    input	wire[`MemAddrBus]			m0_addr_i,
	input	wire[`AXI_DATA_BITS/8-1:0]	m0_strb_i,
    input	wire[`AxiDataBus]			m0_wr_data_i,
	input	wire[11:0]					m0_pulse_bits_i,
	input	wire						m0_m_bus_grant_i,
	input	wire						m0_io_bus_grant_i,

	input	wire						m1_we_i,
    input	wire[`MemAddrBus]			m1_addr_i,
	input	wire[`AXI_DATA_BITS/8-1:0]	m1_strb_i,
    input	wire[`AxiDataBus]			m1_wr_data_i,
	input	wire[11:0]					m1_pulse_bits_i,
	input	wire						m1_m_bus_grant_i,
	input	wire						m1_io_bus_grant_i,

	input	wire						m2_we_i,
    input	wire[`MemAddrBus]			m2_addr_i,
	input	wire[`AXI_DATA_BITS/8-1:0]	m2_strb_i,
    input	wire[`AxiDataBus]			m2_wr_data_i,
	input	wire[11:0]					m2_pulse_bits_i,
	input	wire						m2_m_bus_grant_i,
	input	wire						m2_io_bus_grant_i,

	input	wire						m3_we_i,
    input	wire[`MemAddrBus]			m3_addr_i,
	input	wire[`AXI_DATA_BITS/8-1:0]	m3_strb_i,
    input	wire[`AxiDataBus]			m3_wr_data_i,
	input	wire[11:0]					m3_pulse_bits_i,
	input	wire						m3_m_bus_grant_i,
	input	wire						m3_io_bus_grant_i,

	output	wire						m_we_o,
    output	wire[`MemAddrBus]			m_addr_o,
	output	wire[`AXI_DATA_BITS/8-1:0]	m_strb_o,
    output	wire[`AxiDataBus]			m_wr_data_o,
	output	wire[11:0]					m_pulse_bits_o,

	output	wire[`AxiDataBus]			m0_rd_data_o,
	output	wire[1:0]					m0_errcode_o,
	output	wire[`AxiDataBus]			m1_rd_data_o,
	output	wire[1:0]					m1_errcode_o,
	output	wire[`AxiDataBus]			m2_rd_data_o,
	output	wire[1:0]					m2_errcode_o,
	output	wire[`AxiDataBus]			m3_rd_data_o,
	output	wire[1:0]					m3_errcode_o
	);

	wire m0_grant = (m0_m_bus_grant_i | m0_io_bus_grant_i);
	wire m1_grant = (m1_m_bus_grant_i | m1_io_bus_grant_i);
	wire m2_grant = (m2_m_bus_grant_i | m2_io_bus_grant_i);
	wire m3_grant = (m3_m_bus_grant_i | m3_io_bus_grant_i);

	wire[1:0] m_index = ({2{m0_grant}} & 2'b00)
		| ({2{m1_grant}} & 2'b01)
		| ({2{m2_grant}} & 2'b10)
		| ({2{m3_grant}} & 2'b11);

	assign m_we_o = (m0_grant & m0_we_i)
		| (m1_grant & m1_we_i)
		| (m2_grant & m2_we_i)
		| (m3_grant & m3_we_i);

	assign m_addr_o = ({`MEM_ADDR_WIDTH{m0_grant}} & m0_addr_i)
		| ({`MEM_ADDR_WIDTH{m1_grant}} & m1_addr_i)
		| ({`MEM_ADDR_WIDTH{m2_grant}} & m2_addr_i)
		| ({`MEM_ADDR_WIDTH{m3_grant}} & m3_addr_i);

	assign m_strb_o = ({64{m0_grant}} & m0_strb_i)
		| ({64{m1_grant}} & m1_strb_i)
		| ({64{m2_grant}} & m2_strb_i)
		| ({64{m3_grant}} & m3_strb_i);

	assign m_wr_data_o = ({`AXI_DATA_BITS{m0_grant}} & m0_wr_data_i)
		| ({`AXI_DATA_BITS{m1_grant}} & m1_wr_data_i)
		| ({`AXI_DATA_BITS{m2_grant}} & m2_wr_data_i)
		| ({`AXI_DATA_BITS{m3_grant}} & m3_wr_data_i);

	assign m_pulse_bits_o = ({12{m0_grant}} & m0_pulse_bits_i)
		| ({12{m1_grant}} & m1_pulse_bits_i)
		| ({12{m2_grant}} & m2_pulse_bits_i)
		| ({12{m3_grant}} & m3_pulse_bits_i);

	assign m0_rd_data_o = {`AXI_DATA_BITS{m_index == 2'b00}} & m_rd_data_i;
	assign m1_rd_data_o = {`AXI_DATA_BITS{m_index == 2'b01}} & m_rd_data_i;
	assign m2_rd_data_o = {`AXI_DATA_BITS{m_index == 2'b10}} & m_rd_data_i;
	assign m3_rd_data_o = {`AXI_DATA_BITS{m_index == 2'b11}} & m_rd_data_i;

	assign m0_errcode_o = {2{m_index == 2'b00}} & m_errcode_i;
	assign m1_errcode_o = {2{m_index == 2'b01}} & m_errcode_i;
	assign m2_errcode_o = {2{m_index == 2'b10}} & m_errcode_i;
	assign m3_errcode_o = {2{m_index == 2'b11}} & m_errcode_i;

endmodule
